﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Data;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Runtime;
using System.Runtime.InteropServices;

namespace PickGold.Data
{
	/// <summary>
	/// Provides an interface that supplies dynamic custom type information for an object.
	/// </summary>
	[Serializable]
	[ComVisible(true)]
	[ClassInterface(ClassInterfaceType.AutoDispatch)]
	public class OrmTypeDescriptor : MarshalByRefObject, ICustomTypeDescriptor
	{
		[NonSerialized]
		private static Dictionary<Type, PropertyDescriptorCollection> _GetProperties = new Dictionary<Type, PropertyDescriptorCollection>();

		private object _Entity;
		private string _NamePropertyName;

		/// <summary>
		/// 构造一个自定义类型描述器。
		/// </summary>
		/// <param name="entity">要描述的实体对象。</param>
		public OrmTypeDescriptor(object entity) : this(entity, null){}

		/// <summary>
		/// 构造一个自定义类型描述器。
		/// </summary>
		/// <param name="entity">要描述的实体对象。</param>
		/// <param name="namePropertyName">实体名属性的属性名。</param>
		public OrmTypeDescriptor(object entity, string namePropertyName)
		{
			this._Entity = entity;
			this._NamePropertyName = namePropertyName;
		}

		#region ICustomTypeDescriptor 成员

		/// <summary>
		/// 返回此组件实例的自定义属性的集合。
		/// </summary>
		/// <returns>包含此对象的属性的 System.ComponentModel.AttributeCollection。</returns>
		public static AttributeCollection GetAttributes(object entity)
		{
			return new AttributeCollection(entity.GetType().GetCustomAttributes(true) as Attribute[]);
		}
		AttributeCollection ICustomTypeDescriptor.GetAttributes()
		{
			return OrmTypeDescriptor.GetAttributes(this._Entity);
		}

		/// <summary>
		/// 返回此组件实例的类名。
		/// </summary>
		/// <returns>该对象的类名；如果此类没有名称，则为 null。</returns>
		public static string GetClassName(object entity)
		{
			var type = entity.GetType();
			var cas = type.GetCustomAttributes(typeof(TableAttribute), true) as TableAttribute[];
			if (cas == null || cas.Length == 0)
				return type.Name;

			return cas[0].Name;
		}
		string ICustomTypeDescriptor.GetClassName()
		{
			return OrmTypeDescriptor.GetClassName(this._Entity);
		}

		/// <summary>
		/// 返回此组件实例的名称。
		/// </summary>
		/// <returns>该对象的名称；如果该对象没有名称，则为 null。</returns>
		public static string GetComponentName(object entity, string namePropertyName)
		{
			if (string.IsNullOrEmpty(namePropertyName))
				return null;

			var ps = entity.GetType().GetProperties();
			foreach (var p in ps)
			{
				var cas = p.GetCustomAttributes(typeof(ColumnAttribute), true) as ColumnAttribute[];
				if (cas != null && cas.Length > 0 && string.Compare(cas[0].Name, namePropertyName, StringComparison.OrdinalIgnoreCase) == 0)
					return p.GetValue(entity, null) as string;
			}

			return null;
		}
		string ICustomTypeDescriptor.GetComponentName()
		{
			return OrmTypeDescriptor.GetComponentName(this._Entity, this._NamePropertyName);
		}

		/// <summary>
		/// 返回此组件实例的类型转换器。
		/// </summary>
		/// <returns>表示该对象的转换器的 System.ComponentModel.TypeConverter；如果此对象没有任何 System.ComponentModel.TypeConverter，则为 null。</returns>
		public static TypeConverter GetConverter(object entity)
		{
			return null;
		}
		TypeConverter ICustomTypeDescriptor.GetConverter()
		{
			return OrmTypeDescriptor.GetConverter(this._Entity);
		}

		/// <summary>
		/// 返回此组件实例的默认事件。
		/// </summary>
		/// <returns>表示该对象的默认事件的 System.ComponentModel.EventDescriptor；如果该对象没有事件，则为 null。</returns>
		public static EventDescriptor GetDefaultEvent(object entity)
		{
			return null;
		}
		EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
		{
			return OrmTypeDescriptor.GetDefaultEvent(this._Entity);
		}

		/// <summary>
		/// 返回此组件实例的默认属性。
		/// </summary>
		/// <returns>表示该对象的默认属性的 System.ComponentModel.PropertyDescriptor；如果此对象没有属性，则为 null。</returns>
		public static PropertyDescriptor GetDefaultProperty(object entity, string namePropertyName)
		{
			if (string.IsNullOrEmpty(namePropertyName))
				return null;

			var ps = entity.GetType().GetProperties();
			foreach (var p in ps)
			{
				var cas = p.GetCustomAttributes(typeof(ColumnAttribute), true);
				if (cas == null || cas.Length == 0)
					continue;

				var ca = cas[0] as ColumnAttribute;
				if (string.Compare(ca.Name, namePropertyName, StringComparison.OrdinalIgnoreCase) == 0)
					return new EntityPropertyDescriptor(ca.Name, p.GetCustomAttributes(true) as Attribute[]) { Property = p };
			}

			return null;
		}
		PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
		{
			return OrmTypeDescriptor.GetDefaultProperty(this._Entity, this._NamePropertyName);
		}

		/// <summary>
		/// 返回此组件实例的指定类型的编辑器。
		/// </summary>
		/// <param name="editorBaseType">表示该对象的编辑器的 System.Type。</param>
		/// <returns>表示该对象编辑器的指定类型的 System.Object；如果无法找到编辑器，则为 null。</returns>
		public static object GetEditor(object entity, Type editorBaseType)
		{
			return null;
		}
		object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
		{
			return OrmTypeDescriptor.GetEditor(this._Entity, editorBaseType);
		}

		/// <summary>
		/// 返回此组件实例的事件。
		/// </summary>
		/// <param name="attributes">用作筛选器的 System.Attribute 类型数组。</param>
		/// <returns>表示此组件实例的事件的 System.ComponentModel.EventDescriptorCollection。</returns>
		public static EventDescriptorCollection GetEvents(object entity, Attribute[] attributes)
		{
			return null;
		}
		EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
		{
			return OrmTypeDescriptor.GetEvents(this._Entity, attributes);
		}

		/// <summary>
		/// 返回此组件实例的事件。
		/// </summary>
		/// <returns>表示此组件实例的事件的 System.ComponentModel.EventDescriptorCollection。</returns>
		public static EventDescriptorCollection GetEvents(object entity)
		{
			return OrmTypeDescriptor.GetEvents(entity, null);
		}
		EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
		{
			return OrmTypeDescriptor.GetEvents(this._Entity);
		}

		/// <summary>
		/// 返回此组件实例的属性。
		/// </summary>
		/// <param name="attributes">用作筛选器的 System.Attribute 类型数组。</param>
		/// <returns>表示此组件实例的属性的 System.ComponentModel.PropertyDescriptorCollection。</returns>
		public static PropertyDescriptorCollection GetProperties(object entity, Attribute[] attributes)
		{
			var type = entity.GetType();
			if (OrmTypeDescriptor._GetProperties.ContainsKey(type))
				return OrmTypeDescriptor._GetProperties[type];

			var ps = type.GetProperties();
			var ls = new List<EntityPropertyDescriptor>();
			foreach (var p in ps)
			{
				var cas = p.GetCustomAttributes(true);
				if (attributes != null && attributes.Length > 0)
				{
					foreach (var attribute in attributes)
					{
						foreach (var a in cas)
						{
							if (a.Equals(attribute))
							{
								attributes = null;
								break;
							}
						}
						if (attributes == null)
							break;
					}
					if (attributes != null)
						continue;
				}
				ls.Add(new EntityPropertyDescriptor("@" + p.Name, cas as Attribute[]) { Property = p });
				var cs = p.GetCustomAttributes(typeof(ColumnAttribute), true) as ColumnAttribute[];
				if (cs == null || cs.Length == 0)
					continue;

				ls.Add(new EntityPropertyDescriptor(cs[0].Name, cas as Attribute[]) { Property = p });
			}
			OrmTypeDescriptor._GetProperties[type] = new PropertyDescriptorCollection(ls.ToArray(), true);
			return OrmTypeDescriptor._GetProperties[type];
		}
		PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
		{
			return OrmTypeDescriptor.GetProperties(this._Entity, attributes);
		}

		/// <summary>
		/// 返回此组件实例的属性。
		/// </summary>
		/// <returns>表示此组件实例的属性的 System.ComponentModel.PropertyDescriptorCollection。</returns>
		public static PropertyDescriptorCollection GetProperties(object entity)
		{
			return OrmTypeDescriptor.GetProperties(entity, null);
		}
		PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
		{
			return OrmTypeDescriptor.GetProperties(this._Entity);
		}

		/// <summary>
		/// 返回包含指定的属性描述符所描述的属性的对象。
		/// </summary>
		/// <param name="pd">表示要查找其所有者的属性的 System.ComponentModel.PropertyDescriptor。</param>
		/// <returns>表示指定属性所有者的 System.Object。</returns>
		public static object GetPropertyOwner(object entity, PropertyDescriptor pd)
		{
			return entity;
		}
		object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
		{
			return OrmTypeDescriptor.GetPropertyOwner(this._Entity, pd);
		}

		class EntityPropertyDescriptor : PropertyDescriptor
		{
			/// <summary>
			/// 属性成员
			/// </summary>
			public PropertyInfo Property;

			/// <summary>
			/// 使用指定 System.ComponentModel.MemberDescriptor 中的名称和属性初始化 EntityPropertyDescriptor 类的新实例。
			/// </summary>
			/// <param name="descr">一个 System.ComponentModel.MemberDescriptor，它包含该属性 (Property) 的名称及其属性 (Attribute)。</param>
			public EntityPropertyDescriptor(MemberDescriptor descr) : base(descr) { }
			/// <summary>
			/// 使用指定 System.ComponentModel.MemberDescriptor 中的名称以及同时出现在 System.ComponentModel.MemberDescriptor 和 System.Attribute 数组中的属性初始化 EntityPropertyDescriptor 类的新实例。
			/// </summary>
			/// <param name="descr">一个 System.ComponentModel.MemberDescriptor，包含成员的名称及其属性。</param>
			/// <param name="attrs">一个 System.Attribute 数组，包含要和该属性 (Property) 关联的属性 (Attribute)。</param>
			public EntityPropertyDescriptor(MemberDescriptor descr, Attribute[] attrs) : base(descr, attrs) { }
			/// <summary>
			/// 使用指定的名称和属性初始化 System.ComponentModel.PropertyDescriptor 类的新实例。
			/// </summary>
			/// <param name="name">属性的名称。</param>
			/// <param name="attrs">包含属性 (Property) 属性 (Attribute) 的类型 System.Attribute 的数组。</param>
			public EntityPropertyDescriptor(string name, Attribute[] attrs) : base(name, attrs) { }

			/// <summary>
			/// 当在派生类中被重写时，返回重置对象时是否更改其值。
			/// </summary>
			/// <param name="component">要测试重置功能的组件。</param>
			/// <returns>如果重置组件更改其值，则为 true；否则为 false。</returns>
			public override bool CanResetValue(object component)
			{
				return false;
			}

			/// <summary>
			/// 当在派生类中被重写时，获取该属性绑定到的组件的类型。
			/// </summary>
			public override Type ComponentType
			{
				get
				{
					return this.Property.DeclaringType;
				}
			}

			/// <summary>
			/// 当在派生类中被重写时，获取组件上的属性的当前值。
			/// </summary>
			/// <param name="component">具有为其检索值的属性的组件。</param>
			/// <returns>给定组件的属性的值。</returns>
			public override object GetValue(object component)
			{
				return this.Property.GetValue(component, null);
			}

			/// <summary>
			/// 当在派生类中被重写时，获取指示该属性是否为只读的值。
			/// </summary>
			public override bool IsReadOnly
			{
				get
				{
					return false;
				}
			}

			/// <summary>
			/// 当在派生类中被重写时，获取该属性的类型。
			/// </summary>
			public override Type PropertyType
			{
				get
				{
					return this.Property.PropertyType;
				}
			}

			/// <summary>
			/// 当在派生类中被重写时，将组件的此属性的值重置为默认值。
			/// </summary>
			/// <param name="component">具有要重置为默认值的属性值的组件。</param>
			public override void ResetValue(object component)
			{
				throw new NotSupportedException();
			}

			/// <summary>
			/// 当在派生类中被重写时，将组件的值设置为一个不同的值。
			/// </summary>
			/// <param name="component">具有要进行设置的属性值的组件。</param>
			/// <param name="value">新值。</param>
			public override void SetValue(object component, object value)
			{
				this.Property.SetValue(component, value, null);
			}

			/// <summary>
			/// 当在派生类中被重写时，确定一个值，该值指示是否需要永久保存此属性的值。
			/// </summary>
			/// <param name="component">具有要检查其持久性的属性的组件。</param>
			/// <returns>如果属性应该被永久保存，则为 true；否则为 false。</returns>
			public override bool ShouldSerializeValue(object component)
			{
				return true;
			}
		}

		#endregion
	}
}
